package luzhin;

import java.io.*;

/**
 * Board evaluator. 
 * Matherial, pawns in center, attacks and castling are evaluated.
 * @author lacungus
 *
 */
public class AdvancedEvaluator implements Evaluator, Serializable {

	/**
	 * 
	 */
	public AdvancedEvaluator() {		
	}
	
	private final static long serialVersionUID = 324234235L;
	
	private static final double[] pieceValues = {0.0, 10000.0, 9.0, 3.0, 3.0, 5.0, 1.0, -10000.0, -9.0, -3.0, -3.0, -5.0, -1.0};
	// Infinity
	public static final double INF = 1e10;
	
	private double sum = 0.0;
	private Board board = null;
	private AttackDiagram diagram;
	
	private void evaluateMaterialAndAttacks() {
		int whiteAttacks = 0;
		int blackAttacks = 0;
		for (int i=0;i<Board.SIZE;++i) {
			sum += pieceValues[board.getPiece(i)];
			whiteAttacks += diagram.getWhiteAttacks()[i];
			blackAttacks += diagram.getBlackAttacks()[i];
		}
		double delta = (double) (whiteAttacks) / blackAttacks - 1;
		sum += 2 * delta;
	}

	private void evaluateCenterPawns() {
		if (board.getPiece(Position.getPosition("d4")) == Piece.WP)
			sum += 0.2;
		if (board.getPiece(Position.getPosition("d4")) == Piece.BP)
			sum -= 0.2;
		if (board.getPiece(Position.getPosition("e4")) == Piece.WP)
			sum += 0.2;
		if (board.getPiece(Position.getPosition("e4")) == Piece.BP)
			sum -= 0.2;
		if (board.getPiece(Position.getPosition("d5")) == Piece.WP)
			sum += 0.2;
		if (board.getPiece(Position.getPosition("d5")) == Piece.BP)
			sum -= 0.2;
		if (board.getPiece(Position.getPosition("e5")) == Piece.WP)
			sum += 0.2;
		if (board.getPiece(Position.getPosition("e5")) == Piece.BP)
			sum -= 0.2;
	}
	
	private void evaluateCastling() {
		if (board.isCastledWhite()) {
			sum += 1.0;
		} else {
			if (board.isWhiteKingMoved() || (board.isRookA1Moved() && board.isRookH1Moved()))
				sum -= 1.0;
		}
		if (board.isCastledBlack()) {
			sum -= 1.0;
		} else {
			if (board.isBlackKingMoved() || (board.isRookA8Moved() && board.isRookH8Moved()))
				sum += 1.0;
		}
	}
	
	public double evaluate(Board board, AttackDiagram diagram) {
		this.diagram = diagram;
		sum = 0.0;
		this.board = board;
		evaluateMaterialAndAttacks();
		evaluateCenterPawns();
		evaluateCastling();
		if (!board.isWhiteToMove())
			sum = -sum;
		return sum;
	}
	
	public double evaluate(Board board) {
		AttackDiagramBuilder builder = new AdvancedAttackDiagramBuilder();
		return evaluate(board, builder.buildAttackDiagram(board));
	}
	
	public double getInf() {
		return INF;
	}
}
